let charTypes = require('./char-type');
let tokenTypes = require('./token-types');
let stateTypes = require('./state-types');

let lexerAnalyze = {
  inputs: [],
  index: 0,
  char: '',
  chunkStart: 0,
  chunkEnd: 0,
  strChunk: '',
  state: '',
  expEnd: '',
  result: [],
  analyze(str) {
    this.inputs = str.split('');
    while (this.index < this.inputs.length) {
      this.getChar();
      switch (this.getType(this.char)) {
        case charTypes.letter:
          this.setState(stateTypes.WORD);
          break;
        case charTypes.number:
          this.setState(stateTypes.DIGIT);
          break;
        case charTypes.assign:
          this.setState(stateTypes.ASSIGN);
          break;
        case charTypes.dot:
          this.setState(stateTypes.DOT);
          break;
        case charTypes.pos:
          this.setState(stateTypes.POS);
          break;
        default:
          break;
      }
    }
    this.index++;
    this.setState(stateTypes.END);
    return this.result;
  },
  getType(char) {
    if (/[a-zA-Z]/.test(char)) {
      return charTypes.letter;
    } else if (/\d/.test(char)) {
      return charTypes.number;
    } else if (/[\-=>]/.test(char)) {
      return charTypes.assign;
    } else if (/\./.test(char)) {
      return charTypes.dot;
    } else if (/[@#]/.test(char)) {
      return charTypes.pos;
    } else if (/\s/.test(char)) {
      return charTypes.blank;
    }
  },
  getChar() {
    this.char = this.inputs[this.index];
    if (this.getType(this.char) == 'blank') {
      this.index++;
      this.getChar();
    }
    this.index++;
  },
  addToChunk() {
    this.strChunk += this.char;
  },
  setState(state) {
    if (!this.state) {
      this.state = state;
      this.addToChunk();
    } else {
      if (this.state != state) {
        let prevState = this.state;
        this.stateAdvChange(prevState);
        this.state = state;
      }
      this.addToChunk();
    }
  },
  stateAdvChange(state) {
    if (
      ![
        stateTypes.EXP_STR_START,
        stateTypes.COM_F_START,
        stateTypes.COM_START,
        stateTypes.COM
      ].includes(state)
    ) {
      this.result.push(this.genToken());
      this.strChunk = '';
    }
  },
  genToken() {
    let tokenType = '';
    switch (this.state) {
      case stateTypes.WORD:
        tokenType = tokenTypes.WORD;
        break;
      case stateTypes.DIGIT:
        tokenType = tokenTypes.DIGIT;
        break;
      case stateTypes.DOT:
        tokenType = tokenTypes.DOT;
        break;
      case stateTypes.ASSIGN:
        tokenType = tokenTypes.ASSIGN;
        break;
      case stateTypes.POS:
        tokenType = tokenTypes.POS;
        break;
      default:
        break;
    }
    this.chunkEnd = this.index - 1;
    let result = {
      type: tokenType,
      value: this.strChunk,
      start: this.chunkStart,
      end: this.chunkEnd
    };
    this.chunkStart = this.chunkEnd;
    return result;
  }
};

module.exports = lexerAnalyze;
